<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>

    <div th:replace="fragments/header :: header-meta"/>

    <div th:replace="fragments/header :: header-css"/>

    <link rel="stylesheet" type="text/css" th:href="@{/css/chatvue.css}" />

    <title><span th:utext="#{title}" th:remove="tag"></span> · <span th:utext="#{slogan}" th:remove="tag"></span></title>

</head>
<body>

    <!--TODO: 适配微信-->
    <div id="app-wrapper" style="display: none">
        <div id="app">

            <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-primary">
                <a class="navbar-brand" href="#">{{ title }}</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse"
                        data-target="#navbarCollapse" aria-controls="navbarCollapse"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarCollapse">
                    <ul class="navbar-nav mr-auto">
                        <li class="nav-item active" style="cursor: pointer;">
                            <a class="nav-link" @click="switchAgent">人工客服</a>
                        </li>
                        <li class="nav-item active" style="cursor: pointer;">
                            <a class="nav-link" @click="switchLeaveMessage">我要留言</a>
                        </li>
                        <li class="nav-item active" style="cursor: pointer;">
                            <a class="nav-link" @click="switchRobot">自助答疑</a>
                        </li>
                    </ul>
                    <span class="nav-item">
                    <a class="nav-link" @click="closeWebPage" style="color: white;">
                        <span style="cursor: pointer;"><i class="iconfont icon-close"></i></span>
                    </a>
                </span>
                </div>
            </nav>

            <!--主区域-->
            <main id="main" role="main" style="margin-top: -5px;">

                <el-dialog
                        title="满意度评价"
                        :visible.sync="rateDialogVisible"
                        width="30%"
                        center>
                    <el-rate style="text-align: center; margin-bottom: 40px;"
                             v-model="rateScore"
                             show-text
                             :texts="['极差', '失望', '一般', '满意', '非常满意']">
                    </el-rate>
                    <el-input v-focus type="textarea" :rows="2" placeholder="请输入附言" v-model="rateContent"></el-input>
                    <span slot="footer" class="dialog-footer">
                    <el-button @click="rateDialogVisible = false">取 消</el-button>
                    <el-button type="primary" @click="rate()">评 价</el-button>
                </span>
                </el-dialog>

                <el-dialog title="查看大图"
                           :modal="false"
                           :visible.sync="imageDialogVisible"
                           width="30%">
                    <span><img :src="currentImageUrl" alt="[查看大图]" style="height: 100%; width: 100%;"/></span>
                    <span slot="footer" class="dialog-footer">
                    <el-button type="primary" @click="imageDialogVisible = false">确 定</el-button>
                </span>
                </el-dialog>

                <!-- main + bottom + rightSide-->
                <div id="content" class="row">

                    <!--根据屏幕大小显示与隐藏 https://medium.com/wdstack/bootstrap-4-hidden-visible-dd969a4c5854-->
                    <div class="col-md-10" v-if="!showLeaveMessage">

                        <!--消息记录pc-->
                        <div id="message-pc" class="row d-none d-md-block">

                            <ul class="message-ul" ref="list">
                                <!--<div v-if="thread.id !== 0 && !thread.last" class="pullrefresh" @click="loadMoreMessages()">更多聊天记录</div>-->
                                <li v-for="message in messages" :key="message.id">

                                    <p class="timestamp">
                                        <span>{{ message.createdAt | datetime }}</span><br/>
                                        <span v-if="is_type_notification(message)">{{ message.content }}</span>
                                    </p>

                                    <div v-if="!is_type_notification(message)" :class="{ self: is_self(message) }">
                                        <img v-if="show_header" class="avatar" width="30" height="30" :src="message.user.avatar" />
                                        <div v-if="!is_self(message)" class="nickname">{{ message.user.nickname }}</div>
                                        <div v-if="is_type_text(message)" class="text" v-html="replaceFace(message.content)"></div>
                                        <div v-if="is_type_robot(message)" class="text">
                                            <span v-html="message.content"></span>
                                            <span v-for="answer in message.answers" :key="answer.id">
                                            <br>
                                            <span style="color:#007bff; cursor: pointer;" @click="getAnswer(answer.aid)">{{ answer.question }}</span>
                                        </span>
                                        </div>
                                        <div v-if="is_type_questionnaire(message)" class="text">
                                            <span>{{ message.questionnaire.questionnaireItems[0].title }}</span>
                                            <span v-for="item in message.questionnaire.questionnaireItems[0].questionnaireItemItems" :key="item.id">
                                            <br/>
                                            <span style="color:#007bff; cursor: pointer;" @click="chooseQuestionnaire(item.qid)">{{ item.content }}</span>
                                        </span>
                                        </div>
                                        <div v-if="is_type_company(message)" class="text">
                                            <span>{{ message.content }}</span>
                                            <span v-for="item in message.company.countries" :key="item.id">
                                            <br/>
                                            <span style="color:#007bff; cursor: pointer;" @click="chooseCountry(message.company.cid, item.cid)">{{ item.name }}</span>
                                        </span>
                                        </div>
                                        <div v-if="is_type_workGroup(message)" class="text">
                                            <span>{{ message.content }}</span>
                                            <span v-for="item in message.workGroups" :key="item.id">
                                            <br/>
                                            <span style="color:#007bff; cursor: pointer;" @click="chooseWorkGroup(item.wid)">{{ item.nickname }}</span>
                                        </span>
                                        </div>
                                        <div v-if="is_type_image(message)" class="text">
                                            <img :src="message.imageUrl" alt="[图片]" style="padding-top: 10px; padding-bottom: 10px; width: 100px; height: 100px;" @click="imageClicked(message.imageUrl)"/>
                                        </div>
                                        <div v-if="is_type_file(message)" class="text">
                                            <img src="https://www.bytedesk.com/img/input/file.png" alt="[文件]"
                                                 style="padding-top: 10px; padding-bottom: 10px; width: 25px; height: 20px;"
                                                 @click="fileClicked(message.fileUrl)"/>
                                            <span><a :href="message.fileUrl" target="_blank">查看文件</a></span>
                                        </div>
                                        <div v-if="is_type_voice(message)" class="text">
                                            <img src="https://www.bytedesk.com/img/input/voice_received.png" alt="[语音]"
                                                 style="padding-top: 10px; padding-bottom: 10px; width: 25px; height: 20px;"
                                                 @click="voiceClicked(message.voiceUrl)"/>
                                        </div>

                                        <div class="status" v-if="is_self(message)">
                                            <i v-if="is_sending(message)" class="fa fa-spinner fa-spin" style="font-size:12px"></i>
                                            <i v-if="is_error(message)" class="fa fa-times-circle" style="font-size:12px"></i>
                                        </div>
                                    </div>

                                </li>
                            </ul>

                        </div>

                        <!--输入框pc-->
                        <div id="input-pc" class="row d-none d-md-block">

                            <transition name="showbox">
                                <div class="input-emoji-box" v-show="showEmoji">
                                    <li v-for="item in emojis" :key="item.file">
                                        <img :src="emotionUrl(item.file)" :data="item.title" @click="emotionClicked(item.title)">
                                    </li>
                                </div>
                            </transition>
                            <div class="input-pc-buttons">
                                <li class='iconfont icon-emoji bd-input-emoji' @click="switchEmoji"></li>
                                <el-upload class="bd-upload-image"
                                           :on-preview="handlePreview"
                                           :on-remove="handleRemove"
                                           :before-remove="beforeRemove"
                                           :on-exceed="handleExceed"
                                           :file-list="uploadedImageList"
                                           :data="upload_data"
                                           :name="upload_name"
                                           :action="uploadImageServerUrl"
                                           :show-file-list="false"
                                           :on-success="handleImageUploadSuccess"
                                           :before-upload="beforeImageUpload"
                                           :disabled="disabled">
                                    <li class="iconfont icon-image"></li>
                                </el-upload>
                                <!--<li class='iconfont icon-clear bd-message-clear' @click="clearMessages"></li>-->
                                <li class='iconfont icon-rate bd-message-rate' @click="rateDialogVisible = true"></li>
                                <li v-if="inputTipVisible" class="bd-message-tip">对方正在输入</li>
                            </div>
                            <el-input v-focus type="textarea" :rows="4" placeholder="请输入内容" v-model="inputContent"
                                      @input="onInputChange"
                                      @keyup.enter.native="onKeyUp"></el-input>
                            <!--FIXME: button位置有待优化-->
                            <el-button id="input-pc-send" @click="sendTextMessage" :disabled="sendButtonDisabled"><span>发送</span></el-button>
                            <div id="byteDesk-logo">
                                <img :src="connectedImage" style="margin-left: 10px; margin-top: -3px; height: 12px; width: 12px;" />
                                <a href="https://www.bytedesk.com" target="_blank">客服软件由萝卜丝提供</a>
                            </div>

                        </div>

                        <!--消息记录手机-->
                        <div id="message-mobile" class="row d-block d-md-none">

                            <ul class="message-ul" ref="listm">
                                <!--<div v-if="thread.id !== 0 && !thread.last" class="pullrefresh" @click="loadMoreMessages()">更多聊天记录</div>-->
                                <li v-for="message in messages" :key="message.id">

                                    <p class="timestamp">
                                        <span>{{ message.createdAt | datetime }}</span><br/>
                                        <span v-if="is_type_notification(message)">{{ message.content }}</span>
                                    </p>

                                    <div v-if="!is_type_notification(message)" :class="{ self: is_self(message) }">
                                        <img v-if="show_header" class="avatar-mobile" width="30" height="30" :src="message.user.avatar" />
                                        <div v-if="!is_self(message)" class="nickname">{{ message.user.nickname }}</div>
                                        <div v-if="is_type_text(message)" class="text-mobile" v-html="replaceFace(message.content)"></div>
                                        <div v-if="is_type_robot(message)" class="text-mobile" v-html="replaceFace(message.content)"></div>
                                        <div v-if="is_type_questionnaire(message)" class="text-mobile">
                                            <span>{{ message.questionnaire.questionnaireItems[0].title }}</span>
                                            <span v-for="item in message.questionnaire.questionnaireItems[0].questionnaireItemItems" :key="item.id">
                                            <br/>
                                            <span style="color:#007bff; cursor: pointer;" @click="chooseQuestionnaire(item.qid)">{{ item.content }}</span>
                                        </span>
                                        </div>
                                        <div v-if="is_type_company(message)" class="text-mobile">
                                            <span>{{ message.content }}</span>
                                            <span v-for="item in message.company.countries" :key="item.id">
                                            <br/>
                                            <span style="color:#007bff; cursor: pointer;" @click="chooseCountry(message.company.cid, item.cid)">{{ item.name }}</span>
                                        </span>
                                        </div>
                                        <div v-if="is_type_workGroup(message)" class="text-mobile">
                                            <span>{{ message.content }}</span>
                                            <span v-for="item in message.workGroups" :key="item.id">
                                            <br/>
                                            <span style="color:#007bff; cursor: pointer;" @click="chooseWorkGroup(item.wid)">{{ item.nickname }}</span>
                                        </span>
                                        </div>
                                        <div v-if="is_type_image(message)" class="text-mobile">
                                            <img :src="message.imageUrl" alt="[图片]"
                                                 style="padding-top: 10px; padding-bottom: 10px; width: 100px; height: 100px;"
                                                 @click="imageClicked(message.imageUrl)"/>
                                        </div>
                                        <div v-if="is_type_file(message)" class="text">
                                            <img src="https://www.bytedesk.com/img/input/file_selected.png" alt="[文件]"
                                                 style="padding-top: 10px; padding-bottom: 10px; width: 25px; height: 20px;"
                                                 @click="fileClicked(message.fileUrl)"/>
                                            <span><a :href="message.fileUrl" target="_blank">查看文件</a></span>
                                        </div>
                                        <div v-if="is_type_voice(message)" class="text">
                                            <img src="https://www.bytedesk.com/img/input/voice_received.png" alt="[语音]"
                                                 style="padding-top: 10px; padding-bottom: 10px; width: 25px; height: 20px;"
                                                 @click="voiceClicked(message.voiceUrl)"/>
                                        </div>

                                        <div class="status" v-if="is_self(message)">
                                            <i v-if="is_sending(message)" class="fa fa-spinner fa-spin" style="font-size:12px"></i>
                                            <i v-if="is_error(message)" class="fa fa-times-circle" style="font-size:12px"></i>
                                        </div>
                                    </div>

                                </li>
                            </ul>

                        </div>

                        <!--输入框手机-->
                        <div id="input-mobile" class="row d-block d-md-none">

                            <transition name="showbox">
                                <div class="input-emoji-box" v-show="showEmoji">
                                    <li v-for="item in emojis" :key="item.file">
                                        <img :src="emotionUrl(item.file)" :data="item.title" @click="emotionClicked(item.title)">
                                    </li>
                                </div>
                            </transition>

                            <div class="input-mobile-buttons">
                                <li class='iconfont icon-emoji bd-input-emoji' style="margin-left: 9px;" @click="switchEmoji"></li>
                                <el-upload class="bd-upload-image"
                                           style="margin-left: 10px;"
                                           :on-preview="handlePreview"
                                           :on-remove="handleRemove"
                                           :before-remove="beforeRemove"
                                           :on-exceed="handleExceed"
                                           :file-list="uploadedImageList"
                                           :data="upload_data"
                                           :name="upload_name"
                                           :action="uploadImageServerUrl"
                                           :show-file-list="false"
                                           :on-success="handleImageUploadSuccess"
                                           :before-upload="beforeImageUpload"
                                           :disabled="disabled">
                                    <li class="iconfont icon-image"></li>
                                </el-upload>
                                <!--<li class='iconfont icon-rate bd-message-rate' @click="rateDialogVisible = true"></li>-->
                                <el-input class="input-mobile-input" v-focus placeholder="请输入内容" size="mini"
                                          v-model="inputContent"
                                          @input="onInputChange"
                                          @keyup.enter.native="onKeyUp"></el-input>
                                <el-button size="mini" style="width: 60px;" @click="sendTextMessage" :disabled="sendButtonDisabled">
                                    <span>发送</span>
                                </el-button>
                            </div>

                        </div>

                    </div>

                    <div id="byteDesk-leave" class="col-md-10" v-if="showLeaveMessage">

                        <el-form ref="leaveMessageForm" :model="leaveMessageForm" :rules="rules" label-width="100px" style="width: 30%; margin: auto; margin-top: 60px;">
                            <el-form-item label="手机" prop="mobile">
                                <el-input v-model="leaveMessageForm.mobile" style="width: 250px;" clearable></el-input>
                            </el-form-item>
                            <el-form-item label="邮箱" prop="email">
                                <el-input v-model="leaveMessageForm.email" style="width: 250px;" clearable></el-input>
                            </el-form-item>
                            <el-form-item label="留言" prop="content">
                                <el-input rows="4" type="textarea" v-model="leaveMessageForm.content" style="width: 250px; margin-left: 0px;"></el-input>
                            </el-form-item>
                            <el-form-item>
                                <el-button type="primary" style="width: 100px; margin-left: 70px;" @click="leaveMessage">提交</el-button>
                            </el-form-item>
                        </el-form>

                    </div>

                    <!--右侧信息 - rightSide-->
                    <div id="byteDesk-right" class="col-md-2 d-none d-md-block">

                        <div id="byteDesk-split"></div>

                        <div id="byteDesk-faq">

                            <div style="margin-top: 10px;">常见问题</div>

                            <div class="row" v-for="answer in answers.content" :key="answer.id" style="margin-top: 10px; margin-left: 2px;">

                                <div class="byteDesk-question" @click="getAnswer(answer.aid)">{{ answer.question }}</div>

                            </div>

                        </div>

                        <div id="byteDesk-connected">

                            <img id="byteDesk-connected-image" :src="connectedImage"/>

                            <div>
                                <span v-if="isConnected" style="color: green;">连接正常</span>

                                <span v-if="!isConnected" style="color: red;">连接断开</span>
                            </div>

                        </div>
                    </div>

                </div>

            </main>

        </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.slim.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/js/bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/UAParser.js/0.7.18/ua-parser.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fingerprintjs2/1.8.0/fingerprint2.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.4/sockjs.min.js"></script>

    <!--https://stomp-js.github.io/stomp-websocket/codo/extra/docs-src/Usage.md.html-->
    <!--http://www.jmesnil.net/stomp-websocket/doc/-->
    <!--stomp 1.2: https://stomp.github.io/stomp-specification-1.2.html-->
    <script src="/js/vendor/stomp/1.2/stomp.min.js"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.4.0/index.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>

    <!--http://localhost:8000/chat?uid=201808221551193&wid=201810201758121&type=workGroup&aid=&ph=ph-->
    <script type="text/javascript">
        document.getElementById("app-wrapper").style.display = '';
        var app = new Vue({
            el: '#app',
            data() {
                return {
                    HTTP_HOST: "",
                    STOMP_HOST: "",
                    // HTTP_HOST: 'https://api.bytedesk.com',
                    // STOMP_HOST: 'https://stomp.bytedesk.com',
                    //
                    imageDialogVisible: false,
                    currentImageUrl: '',
                    currentVoiceUrl: '',
                    show_emoji: false,
                    emojiBaseUrl: 'https://chainsnow.oss-cn-shenzhen.aliyuncs.com/emojis/gif/',
                    inputContent: '',
                    messages: [],
                    // 上传图片相关参数
                    upload_headers: {
                        "X-CSRF-TOKEN": "",
                        "X-Requested-With": "XMLHttpRequest",
                        "Accept": "application/json",
                        "Authorization" : "Bearer "
                    },
                    upload_data: {
                        file_name: 'test.png',
                        username: ''
                    },
                    upload_name: 'file',
                    // 接收图片服务器地址
                    uploadImageServerUrl: "/visitor/api/upload/image",
                    // 上传图片结果集, 格式：{name: "", url: ""}
                    uploadedImageList: [],

                    //
                    inputTipVisible: false,

                    /**
                     * 满意度评价相关
                     */
                    // 仅允许评价一次
                    isRated: false,
                    // 是否客服邀请评价
                    isInviteRate: false,
                    // 满意度评价对话框是否可见
                    rateDialogVisible: false,
                    // 满意度评分
                    rateScore: 5,
                    // 满意度附言
                    rateContent: '',

                    /**
                     * 留言
                     */
                    showLeaveMessage: false,
                    leaveMessageForm: {
                        mobile: '',
                        email: '',
                        content: ''
                    },
                    rules: {
                        mobile: [
                            { required: true, message: '请输入手机号码', trigger: 'change' }
                        ],
                        content: [
                            { required: true, message: '请输入留言内容', trigger: 'blur' }
                        ]
                    },

                    /**
                     *
                     */
                    isLoading: false,
                    stompClient: '',
                    sessionId: '',
                    preSessionId: '',
                    browseInviteBIid: '',
                    passport: {
                        token: {
                            access_token: '',
                            expires_in: 0,
                            jti: '',
                            refresh_token: '',
                            scope: '',
                            token_type: ''
                        }
                    },
                    // 左上角标题title
                    title: 'ByteDesk.com',
                    adminUid: '',
                    workGroupWid: '',
                    subDomain: '',
                    client: 'web',
                    // 聊天记录
                    messages: [],
                    thread: {
                        id: 0,
                        tid: ''
                    },
                    // 已经订阅的topic
                    subscribedTopics: [],
                    // 加载聊天记录offset
                    page: 0,
                    // 是否是最后一批聊天记录
                    last: false,
                    // workGroup/visitor/contact/group
                    type: 'workGroup',
                    // 指定客服
                    agentUid: '',
                    // 当前访客用户名
                    uid: '',
                    username: '',
                    password: '',
                    nickname: '',
                    // 本地存储access_token的key
                    token: 'token',
                    isConnected: false,
                    answers: [],
                    isRobot: false,
                    isThreadStarted: false,
                    isThreadClosed: false,

                    //
                    emotionBaseUrl: 'https://chainsnow.oss-cn-shenzhen.aliyuncs.com/emojis/gif/',
                    // 表情
                    emotionMap: {
                        '[微笑]': '100.gif',
                        '[撇嘴]': '101.gif',
                        '[色]': '102.gif',
                        '[发呆]': '103.gif',
                        '[得意]': '104.gif',
                        '[流泪]': '105.gif',
                        '[害羞]': '106.gif',
                        '[闭嘴]': '107.gif',
                        '[睡]': '108.gif',
                        '[大哭]': '109.gif',

                        '[尴尬]': '110.gif',
                        '[发怒]': '111.gif',
                        '[调皮]': '112.gif',
                        '[呲牙]': '113.gif',
                        '[惊讶]': '114.gif',
                        '[难过]': '115.gif',
                        '[酷]': '116.gif',
                        '[冷汗]': '117.gif',
                        '[抓狂]': '118.gif',
                        '[吐]': '119.gif',

                        '[偷笑]': '120.gif',
                        '[愉快]': '121.gif',
                        '[白眼]': '122.gif',
                        '[傲慢]': '123.gif',
                        '[饥饿]': '124.gif',
                        '[困]': '125.gif',
                        '[惊恐]': '126.gif',
                        '[流汗]': '127.gif',
                        '[憨笑]': '128.gif',
                        '[悠闲]': '129.gif',

                        '[奋斗]': '130.gif',
                        '[咒骂]': '131.gif',
                        '[疑问]': '132.gif',
                        '[嘘]': '133.gif',
                        '[晕]': '134.gif',
                        '[疯了]': '135.gif',
                        '[衰]': '136.gif',
                        '[骷髅]': '137.gif',
                        '[敲打]': '138.gif',
                        '[再见]': '139.gif',

                        '[擦汗]': '140.gif',
                        '[抠鼻]': '141.gif',
                        '[鼓掌]': '142.gif',
                        '[糗大了]': '143.gif',
                        '[坏笑]': '144.gif',
                        '[左哼哼]': '145.gif',
                        '[右哼哼]': '146.gif',
                        '[哈欠]': '147.gif',
                        '[鄙视]': '148.gif',
                        '[委屈]': '149.gif',

                        '[快哭]': '150.gif',
                        '[阴险]': '151.gif',
                        '[亲亲]': '152.gif',
                        '[吓]': '153.gif',
                        '[可怜]': '154.gif',
                        '[菜刀]': '155.gif',
                        '[西瓜]': '156.gif',
                        '[啤酒]': '157.gif',
                        '[篮球]': '158.gif',
                        '[乒乓]': '159.gif',

                        '[咖啡]': '160.gif',
                        '[饭]': '161.gif',
                        '[猪头]': '162.gif',
                        '[玫瑰]': '163.gif',
                        '[凋谢]': '164.gif',
                        '[嘴唇]': '165.gif',
                        '[爱心]': '166.gif',
                        '[心碎]': '167.gif',
                        '[蛋糕]': '168.gif',
                        '[闪电]': '169.gif',

                        '[炸弹]': '170.gif',
                        '[刀]': '171.gif',
                        '[足球]': '172.gif',
                        '[瓢虫]': '173.gif',
                        '[便便]': '174.gif',
                        '[月亮]': '175.gif',
                        '[太阳]': '176.gif',
                        '[礼物]': '177.gif',
                        '[拥抱]': '178.gif',
                        '[强]': '179.gif',

                        '[弱]': '180.gif',
                        '[握手]': '181.gif',
                        '[胜利]': '182.gif',
                        '[抱拳]': '183.gif',
                        '[勾引]': '184.gif',
                        '[拳头]': '185.gif',
                        '[差劲]': '186.gif',
                        '[爱你]': '187.gif',
                        '[No]': '188.gif',
                        '[OK]': '189.gif',

                        '[爱情]': '190.gif',
                        '[飞吻]': '191.gif',
                        '[跳跳]': '192.gif',
                        '[发抖]': '193.gif',
                        '[怄火]': '194.gif',
                        '[转圈]': '195.gif',
                        '[磕头]': '196.gif',
                        '[回头]': '197.gif',
                        '[跳绳]': '198.gif',
                        '[投降]': '199.gif',

                        '[激动]': '201.gif',
                        '[乱舞]': '202.gif',
                        '[献吻]': '203.gif',
                        '[左太极]': '204.gif',
                        '[右太极]': '205.gif'
                    },
                    // emoji表情, code代表来自微信端的表情字符，目前已经在服务器端处理替换为title字段，故code字段暂无用途
                    emojis: [
                        { title: '[微笑]', file: '100.gif' },
                        { title: '[撇嘴]', file: '101.gif' },
                        { title: '[色]', file: '102.gif' },
                        { title: '[发呆]', file: '103.gif' },
                        { title: '[得意]', file: '104.gif' },
                        { title: '[流泪]', file: '105.gif' },
                        { title: '[害羞]', file: '106.gif' },
                        { title: '[闭嘴]', file: '107.gif' },
                        { title: '[睡]', file: '108.gif' },
                        { title: '[大哭]', file: '109.gif' },

                        { title: '[尴尬]', file: '110.gif' },
                        { title: '[发怒]', file: '111.gif' },
                        { title: '[调皮]', file: '112.gif' },
                        { title: '[呲牙]', file: '113.gif' },
                        { title: '[惊讶]', file: '114.gif' },
                        { title: '[难过]', file: '115.gif' },
                        { title: '[酷]', file: '116.gif' },
                        { title: '[冷汗]', file: '117.gif' },
                        { title: '[抓狂]', file: '118.gif' },
                        { title: '[吐]', file: '119.gif' },

                        { title: '[偷笑]', file: '120.gif' },
                        { title: '[愉快]', file: '121.gif' },
                        { title: '[白眼]', file: '122.gif' },
                        { title: '[傲慢]', file: '123.gif' },
                        { title: '[饥饿]', file: '124.gif' },
                        { title: '[困]', file: '125.gif' },
                        { title: '[惊恐]', file: '126.gif' },
                        { title: '[流汗]', file: '127.gif' },
                        { title: '[憨笑]', file: '128.gif' },
                        { title: '[悠闲]', file: '129.gif' },

                        { title: '[奋斗]', file: '130.gif' },
                        { title: '[咒骂]', file: '131.gif' },
                        { title: '[疑问]', file: '132.gif' },
                        { title: '[嘘]', file: '133.gif' },
                        { title: '[晕]', file: '134.gif' },
                        { title: '[疯了]', file: '135.gif' },
                        { title: '[衰]', file: '136.gif' },
                        { title: '[骷髅]', file: '137.gif' },
                        { title: '[敲打]', file: '138.gif' },
                        { title: '[再见]', file: '139.gif' },

                        { title: '[擦汗]', file: '140.gif' },
                        { title: '[抠鼻]', file: '141.gif' },
                        { title: '[鼓掌]', file: '142.gif' },
                        { title: '[糗大了]', file: '143.gif' },
                        { title: '[坏笑]', file: '144.gif' },
                        { title: '[左哼哼]', file: '145.gif' },
                        { title: '[右哼哼]', file: '146.gif' },
                        { title: '[哈欠]', file: '147.gif' },
                        { title: '[鄙视]', file: '148.gif' },
                        { title: '[委屈]', file: '149.gif' },

                        { title: '[快哭]', file: '150.gif' },
                        { title: '[阴险]', file: '151.gif' },
                        { title: '[亲亲]', file: '152.gif' },
                        { title: '[吓]', file: '153.gif' }
                    ]
                };
            },
            computed: {
                showEmoji () {
                    return !this.disabled && this.show_emoji
                },
                disabled () {
                    return this.thread.tid === ''
                },
                sendButtonDisabled () {
                    return this.inputContent.trim().length === 0
                },
                threadTopic() {
                    return 'thread.' + this.thread.tid;
                },
                show_header() {
                    return true
                },
                connectedImage () {
                    return this.isConnected ? 'https://bytedesk.oss-cn-shenzhen.aliyuncs.com/util/connected.png'
                        : 'https://bytedesk.oss-cn-shenzhen.aliyuncs.com/util/disconnected.png'
                }
            },
            methods: {
                switchEmoji () {
                    if (!this.disabled) {
                        this.show_emoji = !this.show_emoji
                    }
                },
                switchAgent () {
                    this.showLeaveMessage = false;
                    this.isRobot = false;
                    this.requestThread();
                },
                switchLeaveMessage () {
                    console.log('leave message');
                    this.showLeaveMessage = true;
                },
                switchRobot () {
                    console.log('robot')
                    this.showLeaveMessage = false;
                    this.isRobot = true;
                    this.requestRobot();
                },
                clearMessages () {
                    console.log("clearMessages")
                },
                emotionUrl (file) {
                    return this.emojiBaseUrl + file;
                },
                emotionClicked (emotion) {
                    this.inputContent += emotion;
                    this.show_emoji = false
                },
                imageClicked (imageUrl) {
                    // console.log('image clicked:', imageUrl)
                    this.currentImageUrl = imageUrl;
                    this.imageDialogVisible = true
                },
                fileClicked (fileUrl) {
                    window.open(fileUrl)
                },
                voiceClicked (voiceUrl) {
                    this.currentVoiceUrl = voiceUrl
                    window.open(voiceUrl)
                },
                is_self (message) {
                    return message.user.username === this.username;
                },
                // 发送状态
                is_sending (message) {
                    return message.status === 'sending'
                },
                is_stored (message) {
                    return message.status === 'stored'
                },
                is_received (message) {
                    return message.status === 'received'
                },
                is_error (message) {
                    return message.status === 'error'
                },
                is_read (message) {
                    return message.status === 'readCount'
                },
                // 消息类型
                is_type_text (message) {
                    return message.type === 'text'
                        || message.type === 'notification_thread'
                        || message.type === 'notification_auto_close'
                },
                is_type_robot (message) {
                    return message.type === 'robot'
                },
                is_type_image (message) {
                    return message.type === 'image'
                },
                is_type_file (message) {
                    return message.type === 'file'
                },
                is_type_voice (message) {
                    return message.type === 'voice'
                },
                is_type_questionnaire (message) {
                    return message.type === 'questionnaire'
                },
                is_type_company (message) {
                    return message.type === 'company'
                },
                is_type_workGroup (message) {
                    return message.type === 'workGroup'
                },
                is_type_notification (message) {
                    return message.type !== 'notification_preview'
                        && message.type !== 'notification_thread'
                        && message.type !== 'notification_auto_close'
                        && message.type.startsWith('notification')
                },
                player_url () {
                    return '' + this.currentVoiceUrl
                },
                //  在发送信息之后，将输入的内容中属于表情的部分替换成emoji图片标签
                //  再经过v-html 渲染成真正的图片
                replaceFace (content) {
                    if (content === null || content === undefined) {
                        return ''
                    }
                    var emotionMap = this.emotionMap;
                    var reg = /\[[\u4E00-\u9FA5NoOK]+\]/g
                    var matchresult = content.match(reg)
                    var result = content
                    if (matchresult) {
                        for (var i = 0; i < matchresult.length; i++) {
                            result = result.replace(matchresult[i], '<img height=\'25px\' width=\'25px\' style=\'margin-bottom:4px;\' src=\'' +  this.emotionBaseUrl + emotionMap[matchresult[i]] + '\'>')
                        }
                    }
                    return result
                },
                handleImageDialogClose (done) {
                    done()
                },
                scrollToBottom () {
                    // 聊天记录滚动到最底部
                    let vm = this;
                    this.$nextTick(() => {
                        const ul = vm.$refs.list;
                        if (ul != null) {
                            ul.scrollTop = ul.scrollHeight
                        }
                        const ulm = vm.$refs.listm;
                        if (ulm != null) {
                            ulm.scrollTop = ulm.scrollHeight
                        }
                    })
                },
                pushToMessageArray(message) {
                    let contains = this.messages.some(msg => {
                        return msg.id === message.id
                    })
                    if (!contains) {
                        this.messages.push(message)
                    }
                },
                /**
                 * 工具函数
                 */
                initAxios() {
                    // http response 拦截器
                    axios.interceptors.response.use(
                        response => {
                            return response
                        },
                        error => {
                            if (error.response) {
                                switch (error.response.status) {
                                    case 400:
                                        console.log('axios interception error 400');
                                    // FIXME: 用户名密码无效，则重新分配用户名，并登录
                                    case 401:
                                        console.log('axios interception error 401');
                                    // FIXME:
                                    case 403:
                                        // 401 清除token信息并登录
                                        // 403 无权限，跳转到首页
                                        console.log('axios interception error 403');
                                        localStorage.removeItem(app.token);
                                        if (app.username !== '') {
                                            app.login()
                                        } else {
                                            app.requestUsername();
                                        }
                                }
                            }
                            return 'return axios interception error'
                        })
                },
                getUrlParam(name) {
                    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
                    var r = window.location.search.substr(1).match(reg);  //匹配目标参数
                    if (r != null)
                        return decodeURIComponent(r[2]);
                    return null; //返回参数值
                },
                /**
                 * 上传图片相关函数
                 */
                handleRemove(file, uploadedImageList) {
                    console.log(file, uploadedImageList);
                    // 删除
                    for (var i = 0 ; i < this.uploadedImageList.length; i++) {
                        if (this.uploadedImageList[i].url === file.url) {
                            this.uploadedImageList.splice(i,1);
                        }
                    }
                },
                handlePreview(file) {
                    // TODO: 预览
                    console.log(file);
                },
                handleExceed(files, uploadedImageList) {
                    this.$message.warning(`当前限制选择 3 个文件，本次选择了 ${files.length} 个文件，共选择了 ${files.length + uploadedImageList.length} 个文件`);
                },
                beforeRemove(file, uploadedImageList) {
                    return this.$confirm(`确定移除 ${ file.name }？`);
                },
                handleImageUploadSuccess(result, file) {
                    console.log("upload image success result:", result, " file:", file);
                    if (result.status_code === 200) {
                        // this.uploadedImageList.push({name: file.name, url: result.data});
                        // 发送消息
                        let imageUrl = result.data;
                        this.sendImageMessage(imageUrl);
                    }
                    else {
                        this.$message.error("上传图片错误，请稍后重试...");
                    }
                },
                beforeImageUpload(file) {
                    console.log("before image upload file:", file)
                    const isJPGorPNG = (file.type === 'image/jpeg' || file.type === 'image/png');
                    const isLt2M = file.size / 1024 / 1024 < 2;
                    // 验证图片格式
                    if (!isJPGorPNG) {
                        this.$message.error('上传头像图片只能是 jpg 或 png 格式!');
                    }
                    // 验证图片大小
                    if (!isLt2M) {
                        this.$message.error('上传头像图片大小不能超过 2MB!');
                    }
                    // 设置文件名
                    let filename = moment(new Date()).format('YYYYMMDDHHmmss');
                    if (file.type === 'image/jpeg') {
                        this.upload_data.file_name = filename + '.jpg';
                    }
                    else if (file.type === 'image/png') {
                        this.upload_data.file_name = filename + '.png';
                    }
                    // 返回
                    return isJPGorPNG && isLt2M;
                },
                /**
                 * 1. 首先判断是否已经注册过
                 * 2. 如果已经注册过，则直接调用登录接口
                 * 3. 如果没有注册过，则从服务器请求用户名
                 *
                 * FIXME: 暂未考虑浏览器不支持localStorage的情况
                 */
                requestUsername () {
                    this.username = localStorage.username;
                    this.password = localStorage.password;
                    if (this.username) {
                        if (this.password == null) {
                            this.password = this.username;
                        }
                        this.login();
                    } else {
                        //
                        axios.get(this.HTTP_HOST + '/visitor/api/username', {
                            params: {
                                'subDomain': this.subDomain,
                                'client': this.client
                            }
                        }).then(response => {
                            console.log('username:', response.data);

                            // 登录
                            app.uid = response.data.data.uid;
                            app.username = response.data.data.username;
                            app.password = app.username;
                            app.nickname = response.data.data.nickname;

                            // 本地存储
                            localStorage.uid = app.uid;
                            localStorage.username = app.username;
                            localStorage.password = app.password;

                            // 登录
                            app.login();

                        }).catch(error => {
                            console.log(error)
                        });
                    }
                },
                /**
                 * 保存自定义用户名
                 */
                saveUsername() {
                    //
                    let username = this.getUrlParam("username");
                    let nickname = this.getUrlParam("nickname") == null ? username : this.getUrlParam("username");
                    console.log("username self:", username, nickname);
                    //
                    axios.post(this.HTTP_HOST + '/visitor/api/register/user', {
                        username: username,
                        nickname: nickname,
                        password: username, // 用户名作为默认密码
                        subDomain: this.subDomain,
                        client: this.client
                    }).then(response => {
                        console.log('saveUsername success:', response.data);

                        // 登录
                        app.uid = response.data.data.uid;
                        app.username = response.data.data.username;
                        app.password = app.username;
                        app.nickname = response.data.data.nickname;

                        // 本地存储
                        localStorage.uid = app.uid;
                        localStorage.username = app.username;

                        // 登录
                        app.login();

                    }).catch(error => {
                        console.log(error)
                    });
                },
                /**
                 * 2. oauth2登录
                 */
                login () {
                    axios({
                        method: 'post',
                        url: this.HTTP_HOST + '/oauth/token',
                        params: {
                            'username': this.username,
                            'password': this.password,
                            'grant_type': 'password',
                            'scope': 'all'
                        },
                        auth: {
                            username: 'client',
                            password: 'secret'
                        }
                    }).then(function (response) {
                        console.log('login success: ', response.data);
                        // 本地存储，
                        app.passport.token = response.data;
                        // 本地存储
                        localStorage.username = app.username;
                        localStorage.password = app.password;
                        localStorage.subDomain = app.subDomain;
                        // localStorage 存储
                        localStorage.setItem(app.token, JSON.stringify(response.data));
                        // 请求会话
                        app.requestThread();
                        // 加载常见问题
                        app.getTopAnswers();
                    }).catch(function (error) {
                        console.log(error)
                    })
                },
                /**
                 * 获取设备指纹
                 */
                fingerPrint2() {
                    new Fingerprint2({
                        preprocessor: function(key, value) {
                            if (key == "user_agent") {
                                // https://github.com/faisalman/ua-parser-js
                                var parser = new UAParser(value);
                                var result = JSON.stringify(parser.getResult());
                                console.log(result);
                                return result;
                            } else {
                                return value
                            }
                        }
                    }).get(function(result, components) {
                        // console.log(result); //a hash, representing your device fingerprint
                        // console.log(components); // an array of FP components
                        const params = new URLSearchParams();
                        params.append('hash', result);
                        for (var index in components) {
                            var obj = components[index];
                            var key = obj.key;
                            var value = obj.value;
                            params.append(key, value.toString());
                        }
                        axios.post(app.HTTP_HOST + '/api/fingerprint2/browser?access_token=' + app.passport.token.access_token, params)
                            .then(response => {
                                console.log("fingerprint2: ", response.data);
                            }).catch(error => {
                            console.log(error);
                        });
                    });
                },
                /**
                 * 通知服务器，访客浏览网页中
                 * TODO: 修改为POST请求方式
                 */
                browse() {
                    //
                    var keywords = document.getElementsByName('keywords')[0].content;
                    var description = document.getElementsByName('description')[0].content;
                    var url = window.location.href;
                    url = url.endsWith('#') ? url.substring(0, url.length - 1) : url;
                    //
                    axios.post(this.HTTP_HOST + '/api/browse/notify?access_token=' + this.passport.token.access_token, {
                        adminUid: this.adminUid,
                        workGroupWid: this.workGroupWid,
                        client: this.client,
                        sessionId: this.sessionId,
                        referrer: encodeURI(document.referrer),
                        url: encodeURI(url),
                        title: encodeURI(document.title),
                        keywords: encodeURI(keywords),
                        description: encodeURI(description)
                    }).then(response => {
                        console.log('browse invite accept:', response.data);
                    }).catch(error => {
                        console.log(error)
                    });
                },
                acceptInviteBrowse() {
                    //
                    axios.post(this.HTTP_HOST + '/api/browse/invite/accept?access_token=' + this.passport.token.access_token, {
                        biid: this.browseInviteBIid,
                        client: this.client
                    }).then(response => {
                        console.log('browse invite accept:', response.data);
                        // TODO: 打开对话窗口
                    }).catch(error => {
                        console.log(error)
                    });
                },
                rejectInviteBrowse() {
                    //
                    axios.post(this.HTTP_HOST + '/api/browse/invite/reject?access_token=' + this.passport.token.access_token, {
                        biid: this.browseInviteBIid,
                        client: this.client
                    }).then(response => {
                        console.log('browse invite reject:', response.data);
                    }).catch(error => {
                        console.log(error)
                    });
                },
                /**
                 * 断开重连之后更新session id
                 */
                updateSessionId() {
                    // console.log('session id:', this.sessionId, ' pre session id:', this.preSessionId);
                    axios.post(this.HTTP_HOST + '/api/browse/update/sessionId?access_token=' + this.passport.token.access_token, {
                        sessionId: this.sessionId,
                        preSessionId: this.preSessionId
                    }).then(response => {
                        console.log('update session id:', response.data);
                    }).catch(error => {
                        console.log(error)
                    });
                },
                /**
                 * 请求会话
                 */
                requestThread() {
                    console.log('request thread');
                    //
                    axios.get(this.HTTP_HOST + '/api/thread/request?access_token=' + this.passport.token.access_token, {
                        params: {
                            'uId': this.adminUid,
                            'wId': this.workGroupWid,
                            'type': this.type,
                            'aId': this.agentUid,
                            'client': this.client
                        }
                    }).then(response => {
                        console.log('message:', response.data);
                        let message = response.data.data;
                        if (response.data.status_code === 200) {
                            //
                            app.pushToMessageArray(message);
                            // 1. 保存thread
                            app.thread = message.thread;
                            // 3. 加载聊天记录
                            app.loadMoreMessages();
                            // 4. 设置窗口左上角标题
                            if (app.thread.appointed) {
                                app.title = app.thread.agent.nickname
                            } else {
                                app.title = app.thread.workGroup.nickname;
                            }
                        } else if (response.data.status_code === 201) {
                            message.content = '继续之前会话';
                            app.pushToMessageArray(message);
                            // 1. 保存thread
                            app.thread = message.thread;
                            // 3. 加载聊天记录
                            app.loadMoreMessages();
                            // 4. 头像、标题、描述
                            if (app.thread.appointed) {
                                app.title = app.thread.agent.nickname
                            } else {
                                app.title = app.thread.workGroup.nickname;
                            }
                        } else if (response.data.status_code === 202) {
                            // 排队
                            app.pushToMessageArray(message);
                            // 1. 保存thread
                            app.thread = message.thread;

                        } else if (response.data.status_code === 203) {
                            // 当前非工作时间，请自助查询或留言
                            app.pushToMessageArray(message);
                            // 1. 保存thread
                            app.thread = message.thread;

                            // 4. 设置窗口左上角标题
                            if (app.thread.appointed) {
                                app.title = app.thread.agent.nickname
                            } else {
                                app.title = app.thread.workGroup.nickname;
                            }

                        } else if (response.data.status_code === 204) {
                            // 当前无客服在线，请自助查询或留言
                            //
                            app.pushToMessageArray(message);
                            // 1. 保存thread
                            app.thread = message.thread;

                            // 4. 设置窗口左上角标题
                            if (app.thread.appointed) {
                                app.title = app.thread.agent.nickname
                            } else {
                                app.title = app.thread.workGroup.nickname;
                            }

                            // TODO: 显示留言界面
                            app.switchLeaveMessage();
                        } else if (response.data.status_code === 205) {
                            // 插入业务路由，相当于咨询前提问问卷（选择 或 填写表单）
                            app.pushToMessageArray(message);
                            // 1. 保存thread
                            app.thread = message.thread;
                        } else if (response.data.status_code === -1) {
                            app.login();
                        } else if (response.data.status_code === -2) {
                            // sid 或 wid 错误
                            this.$message.error('siteId或者工作组id错误');
                        } else if (response.data.status_code === -3) {
                            alert('您已经被禁言')
                        }
                        app.scrollToBottom();
                        // 建立长连接
                        app.byteDeskConnect();
                    }).catch(error => {
                        console.log(error)
                    });
                    // 请求指纹
                    this.fingerPrint2();
                },
                /**
                 *
                 */
                requestRobot() {
                    console.log("自助答疑")
                    this.initAnswer()
                },
                /**
                 * 满意度评价
                 */
                rate() {
                    // 隐藏满意度评价dialog
                    this.rateDialogVisible = false;
                    // 判断是否已经评价过，避免重复评价
                    if (app.isRated) {
                        this.$message({ message: '不能重复评价', type: 'warning' });
                        return;
                    }
                    axios.post(this.HTTP_HOST + '/api/rate/do?access_token=' + app.passport.token.access_token, {
                        uid: this.adminUid,
                        wid: this.workGroupWid,
                        aid: this.agentUid,
                        type: this.type,
                        tid: this.thread.tid,
                        score: this.rateScore + "", // 考虑到兼容ios客户端，需要转换为字符串
                        note: this.rateContent,
                        invite: this.isInviteRate ? "1" : "0", // 考虑到兼容ios客户端，需要转换为字符串
                        client: this.client
                    }).then(response => {
                        console.log("rate: ", response.data);
                        this.isRated = true
                        // TODO: 关闭窗口
                    }).catch(error => {
                        console.log(error);
                    });
                },
                /**
                 * 关闭当前窗口
                 */
                closeWebPage() {
                    axios.post(this.HTTP_HOST + '/api/thread/visitor/close?access_token=' + app.passport.token.access_token, {
                        tid: this.thread.tid,
                        client: this.client
                    }).then(response => {
                        console.log("close thread: ", response.data);
                        // 关闭当前窗口
                        if (navigator.userAgent.indexOf("MSIE") > 0) {
                            //
                            if (navigator.userAgent.indexOf("MSIE 6.0") > 0) {
                                window.opener = null;
                                window.close();
                            } else {
                                window.open('', '_top');
                                window.top.close();
                            }
                        }
                        else if (navigator.userAgent.indexOf("Firefox") > 0) {
                            window.location.href = 'about:blank ';
                            window.opener = null;
                            window.open('', '_self', '');
                            window.close();
                        } else {
                            window.opener = null;
                            window.open('', '_self', '');
                            window.close();
                        }
                    }).catch(error => {
                        console.log(error);
                    })
                },
                /**
                 * 加载更多聊天记录
                 * TODO: 访客端暂时不开放聊天记录
                 */
                loadMoreMessages() {
                    // axios.get(this.HTTP_HOST + '/api/messages/user?access_token=' + this.passport.token.access_token, {
                    //     params: {
                    //         'uid': this.uid,
                    //         'page': this.page,
                    //         'size': 100,
                    //         'client': this.client
                    //     }
                    // }).then(response => {
                    //     console.log(response.data);
                    //     if (response.data.status_code === 200)  {
                    //         //
                    //         response.data.data.content.forEach(message => {
                    //             let contains = app.messages.some(msg => {
                    //                 return msg.id === message.id
                    //             });
                    //             if (!contains) {
                    //                 app.messages.unshift(message)
                    //             }
                    //         });
                    //         this.scrollToBottom();
                    //     } else {
                    //         this.$message.warning(response.data.message)
                    //     }
                    //
                    // }).catch(error => {
                    //     console.log(error)
                    // })
                },
                /**
                 * 初始化机器人
                 */
                initAnswer() {
                    axios.get(this.HTTP_HOST + '/api/answer/init?access_token=' + this.passport.token.access_token, {
                        params:{
                            'uid': this.adminUid,
                            'tid': this.thread.tid,
                            'client': this.client
                        }
                    })
                        .then(function (response) {
                            console.log("query answer success:",response.data);
                            if (response.data.status_code === 200)  {
                                //
                                let queryMessage = response.data.data;
                                //
                                app.pushToMessageArray(queryMessage);
                                app.scrollToBottom()
                            } else {
                                this.$message.warning(response.data.message)
                            }
                        })
                        .catch(function (error) {
                            console.log("query answers error:",error);
                        });
                },
                /**
                 * 请求最热问答
                 */
                getTopAnswers() {
                    axios.get(this.HTTP_HOST + '/api/answer/top?access_token=' + this.passport.token.access_token, {
                        params:{
                            'uid': this.adminUid,
                            'client': this.client
                        }
                    })
                        .then(function (response) {
                            console.log("fetch answers success:",response.data);
                            if (response.data.status_code === 200)  {
                                app.answers = response.data.data
                            } else {
                                this.$message.warning(response.data.message)
                            }
                        })
                        .catch(function (error) {
                            console.log("fetch answers error:",error);
                        });
                },
                // 通过aid，请求智能答案
                getAnswer(aid) {
                    axios.get(this.HTTP_HOST + '/api/answer/query?access_token=' + this.passport.token.access_token, {
                        params:{
                            'uid': this.adminUid,
                            'tid': this.thread.tid,
                            'aid': aid,
                            'client': this.client
                        }
                    })
                        .then(function (response) {
                            console.log("query answer success:",response.data);
                            if (response.data.status_code === 200)  {
                                //
                                let queryMessage = response.data.data.query;
                                let replyMessage = response.data.data.reply;
                                //
                                app.pushToMessageArray(queryMessage);
                                app.pushToMessageArray(replyMessage);
                                //
                                app.scrollToBottom()
                            } else {
                                this.$message.warning(response.data.message)
                            }
                        })
                        .catch(function (error) {
                            console.log("query answers error:",error);
                        });
                },
                // 输入内容，请求智能答案
                messageAnswer(content) {
                    axios.get(this.HTTP_HOST + '/api/answer/message?access_token=' + this.passport.token.access_token, {
                        params:{
                            'uid': this.adminUid,
                            'tid': this.thread.tid,
                            'content': content,
                            'client': this.client
                        }
                    })
                        .then(function (response) {
                            console.log("query answer success:",response.data);
                            if (response.data.status_code === 200 ||
                                response.data.status_code === 201)  {
                                //
                                let queryMessage = response.data.data.query;
                                let replyMessage = response.data.data.reply;
                                //
                                app.pushToMessageArray(queryMessage);
                                app.pushToMessageArray(replyMessage);
                                app.scrollToBottom()
                            } else {
                                this.$message.warning(response.data.message)
                            }
                        })
                        .catch(function (error) {
                            console.log("query answers error:",error);
                        });
                },
                rateAnswer(rate) {
                    // TODO: 添加access_token
                    axios.post(this.HTTP_HOST + '/api/answer/rate?access_token=' + this.passport.token.access_token, {
                        uid: this.adminUid,
                        aid: this.aid,
                        rate: rate,
                        client: this.client
                    }).then(response => {
                        console.log("success:", response.data);
                        if (response.data.status_code === 200)  {
                            //
                        } else {
                            this.$message.warning(response.data.message)
                        }
                    }).catch(error => {
                        console.log(error);
                    });
                },
                /**
                 * 留言
                 */
                leaveMessage() {
                    this.$refs['leaveMessageForm'].validate((valid) => {
                        if (valid) {
                            axios.post(this.HTTP_HOST + '/api/leavemsg/save?access_token=' + app.passport.token.access_token, {
                                uid: this.adminUid,
                                wid: this.workGroupWid,
                                aid: this.agentUid,
                                type: this.type,
                                mobile: this.leaveMessageForm.mobile,
                                email: this.leaveMessageForm.email,
                                content: this.leaveMessageForm.content,
                                client: this.client
                            }).then(response => {
                                console.log("leave message: ", response.data);
                                if (response.data.status_code === 200) {
                                    this.$message({ message: '留言成功', type: 'success'});
                                } else {
                                    this.$message.error(response.data.message);
                                }
                            }).catch(error => {
                                console.log(error);
                                this.$message.error('留言失败');
                            });
                        } else {
                            console.log('error submit!!');
                            return false;
                        }
                    });
                },
                /**
                 * 选择问卷答案
                 */
                chooseQuestionnaire(itemQid) {
                    console.log('choose questionnaire: ' + itemQid);
                    // 只允许同时进行一个会话
                    if (this.isThreadStarted) {
                        alert('不能重复请求');
                        return;
                    }
                    axios.get(this.HTTP_HOST + '/api/thread/questionnaire?access_token=' + this.passport.token.access_token, {
                        params:{
                            'tId': this.thread.tid,
                            'itemQid': itemQid,
                            'client': this.client
                        }
                    })
                        .then(function (response) {
                            console.log("choose questionnaire success:",response.data);
                            if (response.data.status_code === 200 ||
                                response.data.status_code === 201)  {
                                //
                                let message = response.data.data;
                                // 添加消息
                                app.pushToMessageArray(message);
                                // 滚动到底部
                                app.scrollToBottom();
                            } else {
                                this.$message.warning(response.data.message)
                            }
                        })
                        .catch(function (error) {
                            console.log("choose questionnaire error:",error);
                        });
                },
                /**
                 * 选择要留学国家
                 */
                chooseCountry(companyCid, countryCid) {
                    axios.get(this.HTTP_HOST + '/api/thread/country?access_token=' + this.passport.token.access_token, {
                        params:{
                            'tId': this.thread.tid,
                            'companyCid': companyCid,
                            'countryCid': countryCid,
                            'client': this.client
                        }
                    })
                        .then(function (response) {
                            console.log("choose country success:",response.data);
                            if (response.data.status_code === 200 ||
                                response.data.status_code === 201)  {
                                //
                                let message = response.data.data;
                                // 添加消息
                                app.pushToMessageArray(message);
                                // 滚动到底部
                                app.scrollToBottom()
                            } else {
                                this.$message.warning(response.data.message)
                            }
                        })
                        .catch(function (error) {
                            console.log("choose country error:",error);
                        });
                },
                /**
                 * 选择工作组
                 */
                chooseWorkGroup(wId) {
                    console.log('choose workgroup:', wId);
                    // 只允许同时进行一个会话
                    if (this.isThreadStarted) {
                        alert('不能重复请求');
                        return;
                    }
                    axios.get(this.HTTP_HOST + '/api/thread/choose/workGroup?access_token=' + this.passport.token.access_token, {
                        params:{
                            'tId': this.thread.tid,
                            'wId': wId,
                            'client': this.client
                        }
                    })
                        .then(function (response) {
                            console.log("choose workGroup success:",response.data);
                            let message = response.data.data;
                            if (response.data.status_code === 200) {
                                //
                                app.pushToMessageArray(message);
                                // 1. 保存thread
                                app.thread = message.thread;
                                // 2. 订阅会话消息
                                app.subscribeTopic(app.threadTopic);
                                // 3. 加载聊天记录
                                app.loadMoreMessages();
                                // 4. 头像、标题、描述
                                if (app.thread.appointed) {
                                    app.title = app.thread.agent.nickname
                                } else {
                                    app.title = app.thread.workGroup.nickname;
                                }
                                // 防止重复点击
                                app.isThreadStarted = true
                            } else if (response.data.status_code === 201) {
                                // message.content = '继续之前会话';
                                app.pushToMessageArray(message);
                                // 1. 保存thread
                                app.thread = message.thread;
                                // 2. 订阅会话消息
                                app.subscribeTopic(app.threadTopic);
                                // 3. 加载聊天记录
                                app.loadMoreMessages();
                                // 4. 头像、标题、描述
                                if (app.thread.appointed) {
                                    app.title = app.thread.agent.nickname
                                } else {
                                    app.title = app.thread.workGroup.nickname;
                                }
                                // 防止重复点击
                                app.isThreadStarted = true
                            } else if (response.data.status_code === 202) {
                                // 排队
                                app.pushToMessageArray(message);
                                // 1. 保存thread
                                app.thread = message.thread;
                                // 防止重复点击
                                app.isThreadStarted = true
                            } else if (response.data.status_code === 203) {
                                // 当前非工作时间，请自助查询或留言
                                app.pushToMessageArray(message);
                                // 1. 保存thread
                                app.thread = message.thread;
                            } else if (response.data.status_code === 204) {
                                // 当前无客服在线，请自助查询或留言
                                app.pushToMessageArray(message);
                                // 1. 保存thread
                                app.thread = message.thread;
                            } else if (response.data.status_code === 205) {
                                // 插入业务路由，相当于咨询前提问问卷（选择 或 填写表单）
                                app.pushToMessageArray(message);
                                // 1. 保存thread
                                app.thread = message.thread;
                            } else if (response.data.status_code === -1) {
                                // access token invalid
                                app.login();
                            } else if (response.data.status_code === -2) {
                                // sid 或 wid 错误
                                this.$message.error('siteId或者工作组id错误');
                            } else if (response.data.status_code === -3) {
                                alert('您已经被禁言')
                            }
                            //
                            app.scrollToBottom()
                        })
                        .catch(function (error) {
                            console.log("choose workGroup error:",error);
                        });
                },
                /**
                 *
                 */
                pushMessage(messageObject) {
                    let contains = app.messages.some(message  =>  {
                        return message.id === messageObject.id
                    })
                    if (!contains) {
                        app.pushToMessageArray(messageObject);
                    }
                },
                guid() {
                    function s4 () {
                        return Math.floor((1 + Math.random()) * 0x10000)
                            .toString(16)
                            .substring(1)
                    }
                    return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4()
                },
                /**
                 * 发送同步消息
                 */
                sendTextMessageSync(content) {
                    this.sendMessageSync('text', content)
                },
                sendImageMessageSync(content) {
                    this.sendMessageSync('image', content)
                },
                sendMessageSync(type, content) {
                    //
                    let localId = this.guid();
                    axios.post(this.HTTP_HOST + '/api/messages/send?access_token=' + this.passport.token.access_token, {
                        tid: this.thread.tid,
                        type: type,
                        content: content,
                        status: 'sending',
                        localId: localId,
                        sessionType: 'thread',
                        client: this.client
                    }).then(response => {
                        console.log('sendMessageSync:' + response.data);
                        if (response.data.status_code !== 200) {
                            alert(response.data.message)
                        }
                    }).catch(error => {
                        console.log(error)
                    })
                },
                /**
                 * 必须添加前缀 '/topic/'
                 * @param topic
                 */
                subscribeTopic(topic) {
                    // 防止重复订阅
                    if (this.subscribedTopics.includes(topic)) {
                        return;
                    }
                    this.subscribedTopics.push(topic);
                    //
                    this.stompClient.subscribe('/topic/' + topic, function (message) {
                        // console.log('message :', message, 'body:', message.body);
                        var messageObject = JSON.parse(message.body);
                        if ((messageObject.type === 'text'
                            || messageObject.type === 'image'
                            || messageObject.type === 'file')
                            && messageObject.user.uid !== app.uid) {
                            //
                            let mid = messageObject.mid;
                            // 发送消息回执：消息送达
                            app.sendReceiptMessage(mid, 'received');
                        }
                        else if (messageObject.type === 'notification_browse_invite') {
                            //
                            app.browseInviteBIid = messageObject.browseInvite.bIid;
                            //
                            app.$msgbox({
                                title: '邀请会话',
                                message: '客服邀请您参加会话',
                                showCancelButton: true,
                                confirmButtonText: '接受',
                                cancelButtonText: '拒绝',
                                beforeClose: (action, instance, done) => {
                                    console.log('beforeClose:', action)
                                    if (action === 'confirm') {
                                        instance.confirmButtonLoading = true;
                                        instance.confirmButtonText = '接入中...';
                                        //
                                        app.acceptInviteBrowse()
                                    } else {
                                        app.rejectInviteBrowse()
                                    }
                                    //
                                    instance.confirmButtonLoading = false;
                                    done()
                                }
                            }).then(action => {
                                console.log('then:', action)
                            })
                        } else if (messageObject.type === 'notification_queue') {
                            // 排队
                        } else if (messageObject.type === 'notification_queue_accept') {
                            // 1. 保存thread
                            app.thread = messageObject.thread;
                            // 2. 订阅会话消息
                            app.subscribeTopic(app.threadTopic);
                        } else if (messageObject.type === 'notification_invite_rate') {
                            // 邀请评价
                            app.rateDialogVisible = true;
                            app.isInviteRate = true;
                        } else if (messageObject.type === 'notification_agent_close'
                            || messageObject.type === 'notification_auto_close') {
                            // TODO: 会话关闭，添加按钮方便用户点击重新请求会话
                            app.isThreadClosed = true
                        } else if (messageObject.type === 'notification_preview') {
                            if (messageObject.user.username !== app.username) {
                                app.inputTipVisible = true;
                                setTimeout(function () {
                                    app.inputTipVisible = false;
                                }, 5000)
                            }
                        }

                        if (messageObject.type !== 'notification_preview'
                            && messageObject.type !== 'notification_receipt'
                            && messageObject.type !== 'notification_connect'
                            && messageObject.type !== 'notification_disconnect') {
                            app.isRobot = false;
                            app.pushMessage(messageObject);
                            app.scrollToBottom()
                        } else {
                            // TODO: 监听客服端输入状态
                        }

                        // https://stomp-js.github.io/stomp-websocket/codo/extra/docs-src/Usage.md.html
                        // and acknowledge it
                        // FIXME: PRECONDITION_FAILED - unknown delivery tag 8
                        // message.ack()
                        // }, {ack: 'client'});
                    });
                },
                /**
                 * 订阅一对一会话,
                 * 必须携带前缀 '/user/'
                 *
                 * @param queue
                 */
                subscribeQueue(queue) {
                    this.stompClient.subscribe('/user/queue/' + queue, function (message) {
                        console.log(queue , ":", message, 'body:', message.body);
                    });
                },
                /**
                 * 输入框变化
                 */
                onInputChange (content) {
                    // console.log(content);
                    // if (content.trim().length > 0) {
                    this.stompClient.send("/app/" + this.threadTopic, {}, JSON.stringify({'type': 'notification_preview', 'content': content, 'client': this.client}));
                    // }
                },
                /**
                 * 发送消息
                 */
                onKeyUp(e) {
                    if (e.keyCode === 13 && this.inputContent.trim().length > 0) {
                        this.inputContent = this.inputContent.trim();
                        this.sendTextMessage()
                    }
                },
                sendTextMessage () {
                    if (this.isThreadClosed) {
                        alert('会话已经结束');
                        return;
                    }
                    //
                    if (this.inputContent.trim().length === 0) {
                        return;
                    }
                    //
                    if (this.isRobot) {
                        this.messageAnswer(this.inputContent);
                    } else {
                        // 发送/广播会话消息
                        this.sendTextMessageSync(this.inputContent)
                        // this.stompClient.send("/app/" + this.threadTopic, {}, JSON.stringify({'type': 'text', 'content': this.inputContent, 'client': this.client}));
                    }
                    // 清空输入框
                    this.inputContent = "";
                    // 清空消息预知
                    this.stompClient.send("/app/" + this.threadTopic, {}, JSON.stringify({'type': 'notification_preview', 'content': '', 'client': this.client}));
                },
                sendImageMessage (imageUrl) {
                    // 发送/广播会话消息
                    this.sendImageMessageSync(imageUrl);
                    // this.stompClient.send("/app/" + this.threadTopic, {}, JSON.stringify({'type': 'image', 'imageUrl': imageUrl, 'client': this.client}));
                },
                sendReceiptMessage (mid, status) {
                    // 收到消息后，向服务器发送回执
                    this.stompClient.send("/app/" + this.threadTopic, {}, JSON.stringify({'type': 'notification_receipt', 'content': mid, 'status': status, 'client': this.client}));
                },
                byteDeskConnect() {
                    var socket = new SockJS(this.STOMP_HOST + '/stomp/?access_token=' + this.passport.token.access_token);
                    this.stompClient = Stomp.over(socket);
                    this.stompClient.reconnect_delay = 1000;
                    // client will send heartbeats every 10000ms, default 10000
                    this.stompClient.heartbeat.outgoing = 20000;
                    // client does not want to receive heartbeats from the server, default 10000
                    this.stompClient.heartbeat.incoming = 20000;
                    // to disable logging, set it to an empty function:
                    // this.stompClient.debug = function (value) {}
                    // 连接bytedesk，如果后台开启了登录，需要登录之后才行
                    this.stompClient.connect({}, function (frame) {
                        // console.log('stompConnected: ' + frame + " username：" + frame.headers['user-name']);
                        app.isConnected = true;
                        // 获取 websocket 连接的 sessionId
                        // FIXME: Uncaught TypeError: Cannot read property '1' of null
                        // const sessionId = /\/([^\/]+)\/websocket/.exec(socket._transport.url)[1];
                        // console.log("connected, session id: " + sessionId);
                        // 订阅会话消息，处理断开重连的情况
                        if (app.thread.tid !== null && app.thread.tid !== undefined && app.thread.tid !== '') {
                            app.subscribeTopic(app.threadTopic);
                        }
                        // 接受通知
                        // app.subscribeQueue('notification');
                        // 订阅错误消息
                        // app.subscribeQueue('errors');
                    }, function (error) {
                        console.log('连接断开【' + error + '】');
                        app.isConnected = false;
                        // 为断开重连做准备
                        app.subscribedTopics = [];
                        // 10秒后重新连接，实际效果：每10秒重连一次，直到连接成功
                        setTimeout(function () {
                            console.log("reconnecting...");
                            app.byteDeskConnect();
                        }, 10000);
                    })
                }
            },
            directives: {
                focus: {
                    // When the bound element is inserted into the DOM...
                    inserted: function (el) {
                        el.focus()
                    }
                }
            },
            created() {
                console.log("created:", localStorage.iframe);
                //
                if (localStorage.iframe === "1") {
                    this.adminUid = localStorage.adminUid;
                    this.workGroupWid = localStorage.workGroupWid;
                    this.subDomain = localStorage.subDomain;
                    this.type = localStorage.type;
                    this.agentUid = localStorage.agentUid;
                } else {
                    this.adminUid = this.getUrlParam("uid");
                    this.workGroupWid = this.getUrlParam("wid");
                    this.subDomain = window.location.host.split('.').length > 2 ? window.location.host.split('.')[0]: '';
                    this.type = this.getUrlParam("type");
                    this.agentUid = this.getUrlParam("aid");
                }
                //
                this.uid = localStorage.uid;
                this.username = localStorage.username;
                this.password = localStorage.password;
                if (this.password === undefined || this.password === null) {
                    this.password = this.username;
                }
                var tokenLocal = localStorage.getItem(this.token);
                if (tokenLocal != null) {
                    this.passport.token = JSON.parse(tokenLocal);
                }
                // TODO: 获取浏览器信息，提交给服务器
                console.log("adminUid：" + this.adminUid + " workGroupWid:" + this.workGroupWid + " subDomain:" + this.subDomain)
            },
            mounted() {
                // console.log("mount");
                this.initAxios();
                if (this.passport.token.access_token !== null
                    && this.passport.token.access_token !== undefined
                    && this.passport.token.access_token !== '') {
                    //
                    this.login()
                } else if (this.username !== null
                    && this.username !== undefined
                    && this.username !== '') {

                    if (this.username === this.getUrlParam("username")) {
                        // 非第一次使用自定义用户名
                        this.login()
                    } else {
                        // 保存自定义用户名到服务器
                        console.log('save username 1')
                        // this.saveUsername();
                        this.requestUsername();
                    }
                } else if (this.getUrlParam("username")) {
                    // 保存自定义用户名到服务器
                    console.log('save username 2')
                    // this.saveUsername();
                    this.requestUsername();
                } else {
                    this.requestUsername();
                }
            },
            filters: {
                datetime (value) {
                    if (typeof value === 'string') {
                        return moment(value).format('YYYY-MM-DD HH:mm:ss')
                    } else {
                        return value
                    }
                }
            }
        });
    </script>

</body>
</html>


<!--// 订阅排队信息，测试成功-->
<!--// app.stompClient.subscribe('/user/queue/position', function (message) {-->
<!--//     console.log('position:', message, 'body:', message.body);-->
<!--// });-->
<!--// 订阅错误消息，测试成功-->
<!--// app.stompClient.subscribe('/user/queue/errors', function (message) {-->
<!--//     console.log('error:', message, 'body:', message.body);-->
<!--// });-->